#ifndef TIEC_TREE_H
#define TIEC_TREE_H

#include <iostream>
#include <iomanip>
#include <ostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include "foundation.h"
#include "symbol.h"
#include "token.h"
#include "util.h"

#define DECL_VISIT_TREE(class_name) \
virtual Result visit##class_name (const PTR<class_name>& tree, Param param) { \
  if constexpr(std::is_void_v<Result>) { \
  } else { \
    return {}; \
  } \
}
#define DEF_TREE_GET_KIND TreeKind getKind() override;
#define DECL_TREE_GET_KIND(cls, kind) \
TreeKind cls::getKind() { \
  return kind; \
}

namespace NS_TIEC {
  /// 语法树类型
  enum struct TreeKind {
    kCompilationUnit = 0,
    kExpression = 1,
    kStatement = 2,

    kIdentifier = 10,
    kAnnotation = 11,
    kBlock = 12,
    kVariable = 13,
    kMethod = 14,
    kEvent = 15,
    kCodeLine = 16,
    kCode = 17,
    kClass = 18,
    kIf = 19,
    kSwitch = 20,
    kCase = 21,
    kForLoop = 22,
    kForEachLoop = 23,
    kWhileLoop = 24,

    kLiteral = 30,

    kArrayType = 50,
    kTemplateType = 51,
    kFieldAccess = 52,
    kMethodInvoke = 53,
    kNewClass = 54,
    kNewArray = 55,
    kArrayAccess = 56,
    kBreak = 57,
    kContinue = 58,
    kReturn = 59,
    kSubscribeEvent = 60,
    kTypeCast = 61,
    kAssign = 62,
    kExchange = 63,
    kInstanceOf = 64,
    kMultiExpr = 65,
    kAwait = 66,
    kParens = 67,
    kUnary = 68,
    kBinary = 69,
    kCodeText = 70,
    kCodeRef = 71,
    kExpressionStatement = 72,

    kErroneous = 100,
  };

  /// 编译单元的类型（源文件为树形结构，每个源文件作为编译单元，定义的语句不一样）
  enum struct CompilationUnitKind {
    // 最顶层编译单元，为类的定义
    kTopLevel = 0,
    // 成员定义单元，只有方法和事件的定义，编译时合成到父级类定义单元
    kMember,
    // 语句定义单元，编译时合并到父级单元，父级单元可以是成员定义单元，也可以是语句定义单元（如果父级为语句单元，要求父级单元有且仅有一个语句）
    kStatement
  };

  /// 方法语法树类型
  enum struct MethodKind {
    // 普通方法
    kCommon = 0,
    // 属性读方法
    kGetter = 1,
    // 属性写方法
    kSetter = 2,
    // 定义事件
    kEventDeclare = 3,
  };

  /// 嵌入式代码类型
  enum struct CodeKind {
    // 单行代码
    kLine = 0,
    // 多行代码
    kLong = 1
  };

  /// 嵌入式代码引用类型
  enum struct CodeRefKind {
    // #this
    kRefThis = 0,
    // 引用变量
    kRefMember = 1,
    // 引用类名
    kRefClass = 2,
    // 引用类成员
    kRefClassMember = 3,
    // 引用原生类名
    kRefNativeClass = 4,
    // 引用编译器特殊字段
    kRefCompiler = 5,
  };

  // 注释类型
  enum struct CommentKind {
    // 单行注释
    kLine = 0,
    // 多行注释
    kLong
  };

  struct TokenPair {
    TiecodeToken token;
    WString text;
  };

  /// 注释
  struct Comment {
    Origin origin;
    CommentKind kind;
    /// 注释原始内容（包含注释符）
    WString raw_content;

    WString getUserContent() const;
  };

  template<typename Param, typename Result>
  class TreeVisitor;

  /// 语法树节点基类
  class Tree {
  public:
    /// 源代码文件位置
    Origin origin;
    /// 表达式执行返回的类型
    PTR<Type> type;

    /// 语法树类型
    virtual TreeKind getKind() = 0;
  };

  /// 表达式基类
  class ExpressionTree : public Tree {
  public:
    DEF_TREE_GET_KIND
  };

  /// 完整语句基类
  class StatementTree : public Tree {
  public:
    DEF_TREE_GET_KIND
  };

  /// 标识符
  class IdentifierTree : public ExpressionTree {
  public:
    PTR<Name> name;
    PTR<Symbol> symbol;

    DEF_TREE_GET_KIND
  };

  /// 注解
  class AnnotationTree : public Tree {
  public:
    /// 注解名称（可能是全名称，如 '附加清单.URI关联'）
    PTR<ExpressionTree> name;
    /// 注解的参数
    PTR<ExpressionTree> arg;

    DEF_TREE_GET_KIND
  };

  /// 可以被注解的成员基类
  class AnnotatedTree : public StatementTree {
  public:
    /// 修饰符
    Modifiers modifiers;
    /// 成员名称
    PTR<IdentifierTree> ident;
    /// 所有注解
    List<PTR<AnnotationTree>> annotations;
    /// 注释
    PTR<Comment> comment;
  };

  /// 代码块
  class BlockTree : public StatementTree {
  public:
    /// 包含的语句
    List<PTR<StatementTree>> statements;

    DEF_TREE_GET_KIND
  };

  /// 变量
  class VariableTree : public AnnotatedTree {
  public:
    /// 变量类型
    PTR<ExpressionTree> type_expr;
    /// 变量初始值
    PTR<Tree> initializer;
    /// 是否为参数
    bool is_parameter{false};
    PTR<VarSymbol> symbol;

    DEF_TREE_GET_KIND
  };

  /// 方法
  class MethodTree : public AnnotatedTree {
  public:
    /// 方法类型
    MethodKind method_kind;
    /// 形式参数
    List<PTR<VariableTree>> parameters;
    /// 返回类型
    PTR<ExpressionTree> return_type;
    /// 方法体
    PTR<BlockTree> body;
    /// Symbol
    PTR<MethodSymbol> symbol;

    DEF_TREE_GET_KIND
  };

  /// 事件
  class EventTree : public MethodTree {
  public:
    /// 事件对象
    PTR<ExpressionTree> event_obj;
    /// 引用的定义事件的Symbol
    PTR<MethodSymbol> decl_symbol;

    DEF_TREE_GET_KIND
  };

  /// 嵌入式代码每一行的单行表示，会储存缩进基数，便于输出时调整缩进
  class CodeLineTree : public StatementTree {
  public:
    /// 包含的语法树，只有CodeTextTree和CodeRefTree
    List<PTR<Tree>> trees;
    /// 缩进基数
    size_t base_indent {0};

    DEF_TREE_GET_KIND
  };

  /// 嵌入式代码
  class CodeTree : public StatementTree {
  public:
    /// 单行代码还是多行代码
    CodeKind code_kind;
    /// tag
    PTR<IdentifierTree> tag;
    /// 每一行的代码
    List<PTR<CodeLineTree>> lines;

    DEF_TREE_GET_KIND
  };

  /// 类
  class ClassTree : public AnnotatedTree {
  public:
    // 父类
    PTR<ExpressionTree> super;
    // 模板类型（PAIR<模板参数变量名, 默认类型名>）
    List<PAIR<PTR<IdentifierTree>, PTR<ExpressionTree>>> templates;
    // 类成员
    List<PTR<AnnotatedTree>> members;
    // 嵌入式代码
    List<PTR<CodeTree>> codes;
    // Symbol
    PTR<ClassSymbol> symbol;

    DEF_TREE_GET_KIND
  };

  /// 编译单元(一个源代码文件)
  class CompilationUnitTree : public AnnotatedTree {
  public:
    /// 编译单元的级别
    CompilationUnitKind unit_kind{CompilationUnitKind::kStatement};
    /// 包名
    PTR<ExpressionTree> pkg;
    /// 所有定义（类、方法、事件、顶级表达式）
    List<PTR<Tree>> defs;
    /// 父级编译单元
    WPTR<CompilationUnitTree> parent;
    /// 包名符号
    PTR<PackageSymbol> symbol;

    DEF_TREE_GET_KIND
  };

  /// 表达式语句
  class ExpressionStatementTree : public StatementTree {
  public:
    PTR<ExpressionTree> expr;

    DEF_TREE_GET_KIND
  };

  /// 如果语句
  class IfTree : public StatementTree {
  public:
    // 条件
    PTR<ExpressionTree> condition;
    // 条件成立部分的语句
    PTR<BlockTree> then_part;
    // 否则
    PTR<StatementTree> else_part;

    DEF_TREE_GET_KIND
  };

  /// 假如-是
  class CaseTree : public StatementTree {
  public:
    /// 条件
    List<PTR<ExpressionTree>> conditions;
    /// 语句
    PTR<BlockTree> body;

    DEF_TREE_GET_KIND
  };

  /// 假如-是 语句
  class SwitchTree : public StatementTree {
  public:
    // 条件
    PTR<ExpressionTree> selector;
    // case
    List<PTR<CaseTree>> cases;

    DEF_TREE_GET_KIND
  };

  // 所有循环的基类
  class LoopTree : public StatementTree {
  public:
    PTR<BlockTree> body;
  };
  /// 起始值到终止值的循环语句
  class ForLoopTree : public LoopTree {
  public:
    // 赋值
    PTR<ExpressionTree> target;
    // 起始值
    PTR<ExpressionTree> start;
    // 终止值
    PTR<ExpressionTree> end;
    // 步进值
    PTR<ExpressionTree> step;

    DEF_TREE_GET_KIND
  };

  /// 遍历循环
  class ForEachTree : public LoopTree {
  public:
    // 遍历源
    PTR<ExpressionTree> source;
    // 赋值变量1
    PTR<ExpressionTree> var1;
    // 赋值变量2
    PTR<ExpressionTree> var2;

    DEF_TREE_GET_KIND
  };

  /// 条件循环
  class WhileLoopTree : public LoopTree {
  public:
    // 条件
    PTR<ExpressionTree> condition;

    DEF_TREE_GET_KIND
  };

  /// 常量
  class LiteralTree : public ExpressionTree{
  public:
    /// 常量值
    ConstValue value {ConstValue::kNull};

    DEF_TREE_GET_KIND;
  };

  /// 数组类型表达式
  class ArrayTypeTree : public ExpressionTree {
  public:
    // 类型
    PTR<ExpressionTree> expr;
    // 数组容量
    PTR<ExpressionTree> size;

    DEF_TREE_GET_KIND
  };

  /// 泛型类型表达式
  class TemplateTypeTree : public ExpressionTree {
  public:
    // 类型
    PTR<ExpressionTree> expr;
    // 泛型参数类型
    List<PTR<ExpressionTree>> args;

    DEF_TREE_GET_KIND
  };

  /// 字段访问表达式
  class FieldAccessTree : public ExpressionTree {
  public:
    // 前缀
    PTR<ExpressionTree> prefix;
    // 字段名称
    PTR<IdentifierTree> ident;
    PTR<Symbol> symbol;

    DEF_TREE_GET_KIND
  };

  /// 调用方法表达式
  class MethodInvokeTree : public ExpressionTree {
  public:
    // 方法名表达式
    PTR<ExpressionTree> method;
    // 传入参数
    List<PTR<ExpressionTree>> args;

    DEF_TREE_GET_KIND
  };

  /// 创建对象表达式
  class NewClassTree : public ExpressionTree {
  public:
    // 对象类型
    PTR<ExpressionTree> class_name;

    DEF_TREE_GET_KIND
  };

  /// 创建数组表达式
  class NewArrayTree : public ExpressionTree {
  public:
    // 数组元素
    List<PTR<ExpressionTree>> elements;

    DEF_TREE_GET_KIND
  };

  /// 数组访问表达式
  class ArrayAccessTree : public ExpressionTree {
  public:
    // 数组对象
    PTR<ExpressionTree> selected;
    // 索引
    PTR<ExpressionTree> index;

    DEF_TREE_GET_KIND
  };

  /// 退出循环 表达式
  class BreakTree : public ExpressionTree {
  public:
    DEF_TREE_GET_KIND
  };

  /// 跳过循环 表达式
  class ContinueTree : public ExpressionTree {
  public:
    DEF_TREE_GET_KIND
  };

  /// 返回值 表达式
  class ReturnTree : public ExpressionTree {
  public:
    // 返回值
    PTR<ExpressionTree> value;

    DEF_TREE_GET_KIND
  };

  /// 订阅事件 表达式
  class SubscribeEventTree : public ExpressionTree {
  public:
    // 要订阅事件的变量
    List<PTR<IdentifierTree>> vars;

    DEF_TREE_GET_KIND
  };

  /// 强转类型 表达式
  class TypeCastTree : public ExpressionTree {
  public:
    // 要强转的对象
    PTR<ExpressionTree> expr;
    // 目标类型
    PTR<ExpressionTree> type_expr;

    DEF_TREE_GET_KIND
  };

  /// 赋值表达式
  class AssignTree : public ExpressionTree {
  public:
    // 要赋值的变量
    PTR<ExpressionTree> var;
    // 赋值
    PTR<ExpressionTree> value;

    DEF_TREE_GET_KIND
  };

  /// 交换值表达式
  class ExchangeTree : public ExpressionTree {
  public:
    // 左值
    PTR<ExpressionTree> left;
    // 右值
    PTR<ExpressionTree> right;

    DEF_TREE_GET_KIND
  };

  /// 属于 表达式
  class InstanceOfTree : public ExpressionTree {
  public:
    // 对象
    PTR<ExpressionTree> expr;
    // 类型
    PTR<ExpressionTree> type_expr;

    DEF_TREE_GET_KIND
  };

  /// 多元表达式
  class MultiExprTree : public ExpressionTree {
  public:
    // 所有表达式
    List<PTR<ExpressionTree>> expressions;

    DEF_TREE_GET_KIND
  };

  /// 异步等待表达式
  class AwaitTree : public ExpressionTree {
  public:
    // 等待的对象
    PTR<ExpressionTree> expr;

    DEF_TREE_GET_KIND
  };

  /// 括号表达式
  class ParensTree : public ExpressionTree {
  public:
    // 括号里的表达式
    PTR<ExpressionTree> expr;

    DEF_TREE_GET_KIND
  };

  /// 一元表达式
  class UnaryTree : public ExpressionTree {
  public:
    // 表达式
    PTR<ExpressionTree> expr;
    // 操作符token
    TiecodeToken op_token;

    DEF_TREE_GET_KIND
  };

  /// 二元表达式
  class BinaryTree : public ExpressionTree {
  public:
    // 左节点
    PTR<ExpressionTree> left;
    // 右节点
    PTR<ExpressionTree> right;
    // 运算符
    TiecodeToken op_token;

    DEF_TREE_GET_KIND
  };

  /// 嵌入式代码代码文本
  class CodeTextTree : public ExpressionTree {
  public:
    // 文本内容
    WString content;

    DEF_TREE_GET_KIND
  };

  /// 嵌入式代码引用表达式
  class CodeRefTree : public ExpressionTree {
  public:
    // 引用对象
    PTR<ExpressionTree> expr;
    // 引用分类
    CodeRefKind ref_kind;

    DEF_TREE_GET_KIND
  };

  /// 错误代码表达式
  class ErroneousTree : public ExpressionTree {
  public:
    // 错误的token序列
    List<TokenPair> tokens;
    // 错误信息
    String msg;

    DEF_TREE_GET_KIND
  };


  template<typename Result, typename Param>
  class TreeVisitor {
  public:

#define CASE_VISIT(kind, cls) \
  case kind: { \
    PTR<cls> cast_tree = std::static_pointer_cast<cls>(tree); \
    return visit##cls(cast_tree, param); \
  }

    virtual Result visitTree(const PTR<Tree>& tree, Param param) {
      if (tree == nullptr) {
        if constexpr (std::is_void_v<Result>) {
          return;
        } else {
          return {};
        }
      }
      switch (tree->getKind()) {
      CASE_VISIT(TreeKind::kIdentifier, IdentifierTree)
      CASE_VISIT(TreeKind::kAnnotation, AnnotationTree)
      CASE_VISIT(TreeKind::kBlock, BlockTree)
      CASE_VISIT(TreeKind::kVariable, VariableTree)
      CASE_VISIT(TreeKind::kMethod, MethodTree)
      CASE_VISIT(TreeKind::kEvent, EventTree)
      CASE_VISIT(TreeKind::kCodeLine, CodeLineTree)
      CASE_VISIT(TreeKind::kCode, CodeTree)
      CASE_VISIT(TreeKind::kClass, ClassTree)
      CASE_VISIT(TreeKind::kCompilationUnit, CompilationUnitTree)
      CASE_VISIT(TreeKind::kIf, IfTree)
      CASE_VISIT(TreeKind::kCase, CaseTree)
      CASE_VISIT(TreeKind::kSwitch, SwitchTree)
      CASE_VISIT(TreeKind::kForLoop, ForLoopTree)
      CASE_VISIT(TreeKind::kForEachLoop, ForEachTree)
      CASE_VISIT(TreeKind::kWhileLoop, WhileLoopTree)
      CASE_VISIT(TreeKind::kLiteral, LiteralTree)
      CASE_VISIT(TreeKind::kArrayType, ArrayTypeTree)
      CASE_VISIT(TreeKind::kTemplateType, TemplateTypeTree)
      CASE_VISIT(TreeKind::kFieldAccess, FieldAccessTree)
      CASE_VISIT(TreeKind::kMethodInvoke, MethodInvokeTree)
      CASE_VISIT(TreeKind::kNewClass, NewClassTree)
      CASE_VISIT(TreeKind::kNewArray, NewArrayTree)
      CASE_VISIT(TreeKind::kArrayAccess, ArrayAccessTree)
      CASE_VISIT(TreeKind::kBreak, BreakTree)
      CASE_VISIT(TreeKind::kContinue, ContinueTree)
      CASE_VISIT(TreeKind::kReturn, ReturnTree)
      CASE_VISIT(TreeKind::kSubscribeEvent, SubscribeEventTree)
      CASE_VISIT(TreeKind::kTypeCast, TypeCastTree)
      CASE_VISIT(TreeKind::kAssign, AssignTree)
      CASE_VISIT(TreeKind::kExchange, ExchangeTree)
      CASE_VISIT(TreeKind::kInstanceOf, InstanceOfTree)
      CASE_VISIT(TreeKind::kMultiExpr, MultiExprTree)
      CASE_VISIT(TreeKind::kAwait, AwaitTree)
      CASE_VISIT(TreeKind::kParens, ParensTree)
      CASE_VISIT(TreeKind::kUnary, UnaryTree)
      CASE_VISIT(TreeKind::kBinary, BinaryTree)
      CASE_VISIT(TreeKind::kCodeText, CodeTextTree)
      CASE_VISIT(TreeKind::kCodeRef, CodeRefTree)
      CASE_VISIT(TreeKind::kExpressionStatement, ExpressionStatementTree)
      CASE_VISIT(TreeKind::kErroneous, ErroneousTree)
      default:
        throw std::runtime_error("Unknown TreeKind");
      }
    }

#undef CASE_VISIT

    template<typename T>
    Result visitTrees(const List<PTR<T>>& trees, Param param) {
      if (trees.empty()) {
        if constexpr (std::is_void_v<Result>) {
          return;
        } else {
          return {};
        }
      }
      if constexpr (std::is_void_v<Result>) {
        trees.forEach([this, &param](const PTR<T>& tree) {
          visitTree(tree, param);
        });
        return;
      } else {
        Result r;
        trees.forEach([this, &r, &param](const PTR<T>& tree) {
          r = visitTree(tree, param);
        });
        return r;
      }
    }

    DECL_VISIT_TREE(IdentifierTree)
    DECL_VISIT_TREE(AnnotationTree)
    DECL_VISIT_TREE(BlockTree)
    DECL_VISIT_TREE(VariableTree)
    DECL_VISIT_TREE(MethodTree)
    DECL_VISIT_TREE(EventTree)
    DECL_VISIT_TREE(CodeLineTree)
    DECL_VISIT_TREE(CodeTree)
    DECL_VISIT_TREE(ClassTree)
    DECL_VISIT_TREE(CompilationUnitTree)
    DECL_VISIT_TREE(ExpressionStatementTree)
    DECL_VISIT_TREE(IfTree)
    DECL_VISIT_TREE(CaseTree)
    DECL_VISIT_TREE(SwitchTree)
    DECL_VISIT_TREE(ForLoopTree)
    DECL_VISIT_TREE(ForEachTree)
    DECL_VISIT_TREE(WhileLoopTree)
    DECL_VISIT_TREE(LiteralTree)
    DECL_VISIT_TREE(ArrayTypeTree)
    DECL_VISIT_TREE(TemplateTypeTree)
    DECL_VISIT_TREE(FieldAccessTree)
    DECL_VISIT_TREE(MethodInvokeTree)
    DECL_VISIT_TREE(NewClassTree)
    DECL_VISIT_TREE(NewArrayTree)
    DECL_VISIT_TREE(ArrayAccessTree)
    DECL_VISIT_TREE(BreakTree)
    DECL_VISIT_TREE(ContinueTree)
    DECL_VISIT_TREE(ReturnTree)
    DECL_VISIT_TREE(SubscribeEventTree)
    DECL_VISIT_TREE(TypeCastTree)
    DECL_VISIT_TREE(AssignTree)
    DECL_VISIT_TREE(ExchangeTree)
    DECL_VISIT_TREE(InstanceOfTree)
    DECL_VISIT_TREE(MultiExprTree)
    DECL_VISIT_TREE(AwaitTree)
    DECL_VISIT_TREE(ParensTree)
    DECL_VISIT_TREE(UnaryTree)
    DECL_VISIT_TREE(BinaryTree)
    DECL_VISIT_TREE(CodeTextTree)
    DECL_VISIT_TREE(CodeRefTree)
    DECL_VISIT_TREE(ErroneousTree)
  };

  template<typename Result, typename Param>
  class TreeScanner : public TreeVisitor<Result, Param> {
  public:
    virtual Result scan(const PTR<Tree>& tree, Param param) {
      return this->visitTree(tree, param);
    }

    template<typename T>
    Result scan(const List<PTR<T>>& trees, Param param) {
      if (trees.empty()) {
        return {};
      }
      Result r;
      bool first = true;
      trees.forEach([this, &param, &r, &first](const PTR<T>& tree) {
        if (first) {
          r = scan(tree, param);
          first = false;
        } else {
          r = scanAndReduce(tree, param, r);
        }
      });
      return r;
    }

    virtual Result reduce(Result& r1, Result& r2) {
      return r1;
    }

    Result visitIdentifierTree(const PTR<IdentifierTree>& tree, Param param) override {
      return {};
    }

    Result visitAnnotationTree(const PTR<AnnotationTree>& tree, Param param) override {
      Result r = scan(tree->arg, param);
      return scanAndReduce(tree->name, param, r);
    }

    Result visitBlockTree(const PTR<BlockTree>& tree, Param param) override {
      return scan(tree->statements, param);
    }

    Result visitVariableTree(const PTR<VariableTree>& tree, Param param) override {
      Result r = scan(tree->type_expr, param);
      r = scanAndReduce(tree->initializer, param, r);
      return r;
    }

    Result visitMethodTree(const PTR<MethodTree>& tree, Param param) override {
      Result r = scan(tree->parameters, param);
      r = scanAndReduce(tree->return_type, param, r);
      r = scanAndReduce(tree->body, param, r);
      return r;
    }

    Result visitEventTree(const PTR<EventTree>& tree, Param param) override {
      Result r = scan(tree->event_obj, param);
      r = scanAndReduce(tree->parameters, param, r);
      r = scanAndReduce(tree->return_type, param, r);
      r = scanAndReduce(tree->body, param, r);
      return r;
    }

    Result visitCodeLineTree(const PTR<CodeLineTree>& tree, Param param) override {
      Result r = scan(tree->trees, param);
      return r;
    }

    Result visitCodeTree(const PTR<CodeTree>& tree, Param param) override {
      Result r = scan(tree->lines, param);
      return r;
    }

    Result visitClassTree(const PTR<ClassTree>& tree, Param param) override {
      Result r = scan(tree->super, param);
      const size_t size = tree->templates.size();
      for (size_t i = 0; i < size; i++) {
        const PAIR<PTR<IdentifierTree>, PTR<ExpressionTree>>& pair = tree->templates[i];
        r = scanAndReduce(pair.first, param, r);
        r = scanAndReduce(pair.second, param, r);
      }
      r = scanAndReduce(tree->members, param, r);
      r = scanAndReduce(tree->codes, param, r);
      return r;
    }

    Result visitCompilationUnitTree(const PTR<CompilationUnitTree>& tree, Param param) override {
      Result r = scan(tree->pkg, param);
      r = scanAndReduce(tree->defs, param, r);
      return r;
    }

    Result visitExpressionStatementTree(const PTR<ExpressionStatementTree>& tree, Param param) override {
      return scan(tree->expr, param);
    }

    Result visitIfTree(const PTR<IfTree>& tree, Param param) override {
      Result r = scan(tree->condition, param);
      r = scanAndReduce(tree->then_part, param, r);
      r = scanAndReduce(tree->else_part, param, r);
      return r;
    }

    Result visitCaseTree(const PTR<CaseTree>& tree, Param param) override {
      Result r = scan(tree->conditions, param);
      r = scanAndReduce(tree->body, param, r);
      return r;
    }

    Result visitSwitchTree(const PTR<SwitchTree>& tree, Param param) override {
      Result r = scan(tree->selector, param);
      r = scanAndReduce(tree->cases, param, r);
      return r;
    }

    Result visitForLoopTree(const PTR<ForLoopTree>& tree, Param param) override {
      Result r = scan(tree->target, param);
      r = scanAndReduce(tree->start, param, r);
      r = scanAndReduce(tree->end, param, r);
      r = scanAndReduce(tree->step, param, r);
      r = scanAndReduce(tree->body, param, r);
      return r;
    }

    Result visitForEachTree(const PTR<ForEachTree>& tree, Param param) override {
      Result r = scan(tree->source, param);
      r = scanAndReduce(tree->var1, param, r);
      r = scanAndReduce(tree->var2, param, r);
      r = scanAndReduce(tree->body, param, r);
      return r;
    }

    Result visitWhileLoopTree(const PTR<WhileLoopTree>& tree, Param param) override {
      Result r = scan(tree->condition, param);
      r = scanAndReduce(tree->body, param, r);
      return r;
    }

    // 字面量类型没有子节点，直接返回默认结果
    Result visitLiteralTree(const PTR<LiteralTree>& tree, Param param) override {
      return {};
    }

    Result visitArrayTypeTree(const PTR<ArrayTypeTree>& tree, Param param) override {
      Result r = scan(tree->expr, param);
      r = scanAndReduce(tree->size, param, r);
      return r;
    }

    Result visitTemplateTypeTree(const PTR<TemplateTypeTree>& tree, Param param) override {
      Result r = scan(tree->expr, param);
      r = scanAndReduce(tree->args, param, r);
      return r;
    }

    Result visitFieldAccessTree(const PTR<FieldAccessTree>& tree, Param param) override {
      Result r = scan(tree->prefix, param);
      // ident只是起个保存名称的作用，应该不用scan
      //r = scanAndReduce(tree->ident, param, r);
      return r;
    }

    Result visitMethodInvokeTree(const PTR<MethodInvokeTree>& tree, Param param) override {
      Result r = scan(tree->method, param);
      r = scanAndReduce(tree->args, param, r);
      return r;
    }

    Result visitNewClassTree(const PTR<NewClassTree>& tree, Param param) override {
      return scan(tree->class_name, param);
    }

    Result visitNewArrayTree(const PTR<NewArrayTree>& tree, Param param) override {
      return scan(tree->elements, param);
    }

    Result visitArrayAccessTree(const PTR<ArrayAccessTree>& tree, Param param) override {
      Result r = scan(tree->selected, param);
      r = scanAndReduce(tree->index, param, r);
      return r;
    }

    // Break和Continue没有子节点
    Result visitBreakTree(const PTR<BreakTree>& tree, Param param) override {
      return {};
    }

    Result visitContinueTree(const PTR<ContinueTree>& tree, Param param) override {
      return {};
    }

    Result visitReturnTree(const PTR<ReturnTree>& tree, Param param) override {
      return scan(tree->value, param);
    }

    Result visitSubscribeEventTree(const PTR<SubscribeEventTree>& tree, Param param) override {
      return scan(tree->vars, param);
    }

    Result visitTypeCastTree(const PTR<TypeCastTree>& tree, Param param) override {
      Result r = scan(tree->expr, param);
      r = scanAndReduce(tree->type_expr, param, r);
      return r;
    }

    Result visitAssignTree(const PTR<AssignTree>& tree, Param param) override {
      Result r = scan(tree->var, param);
      r = scanAndReduce(tree->value, param, r);
      return r;
    }

    Result visitExchangeTree(const PTR<ExchangeTree>& tree, Param param) override {
      Result r = scan(tree->left, param);
      r = scanAndReduce(tree->right, param, r);
      return r;
    }

    Result visitInstanceOfTree(const PTR<InstanceOfTree>& tree, Param param) override {
      Result r = scan(tree->expr, param);
      r = scanAndReduce(tree->type_expr, param, r);
      return r;
    }

    Result visitMultiExprTree(const PTR<MultiExprTree>& tree, Param param) override {
      return scan(tree->expressions, param);
    }

    Result visitAwaitTree(const PTR<AwaitTree>& tree, Param param) override {
      return scan(tree->expr, param);
    }

    Result visitParensTree(const PTR<ParensTree>& tree, Param param) override {
      return scan(tree->expr, param);
    }

    Result visitUnaryTree(const PTR<UnaryTree>& tree, Param param) override {
      return scan(tree->expr, param);
    }

    Result visitBinaryTree(const PTR<BinaryTree>& tree, Param param) override {
      Result r = scan(tree->left, param);
      r = scanAndReduce(tree->right, param, r);
      return r;
    }

    Result visitCodeTextTree(const PTR<CodeTextTree>& tree, Param param) override {
      return {};
    }

    Result visitCodeRefTree(const PTR<CodeRefTree>& tree, Param param) override {
      return scan(tree->expr, param);
    }

    Result visitErroneousTree(const PTR<ErroneousTree>& tree, Param param) override {
      return {};
    }

  private:
    Result scanAndReduce(const PTR<Tree>& tree, Param param, Result& last_result) {
      Result r = scan(tree, param);
      return reduce(r, last_result);
    }

    template<typename T>
    Result scanAndReduce(const List<PTR<T>>& trees, Param param, Result& last_result) {
      Result r = scan(trees, param);
      return reduce(r, last_result);
    }
  };
  
  /// 符号填充和语义分析时的上下文环境节点
  struct EnvNode {
    /// 当前所处的编译单元根节点
    PTR<CompilationUnitTree> root;
    /// 当前所处类
    PTR<ClassTree> klass;
    /// 当前所处方法（可能是事件）
    PTR<MethodTree> method;
    /// 当前所处作用域
    PTR<MutableScope> scope;
    /// 当前所处语法树，用于向子节点传递
    PTR<Tree> tree;
    /// 是否为模板类型参数
    bool is_template_arg {false};
    /// 当前上下文的外层节点
    EnvNode* outer;

    EnvNode(PTR<CompilationUnitTree> root, PTR<ClassTree> klass, PTR<MethodTree> method, PTR<MutableScope> scope, PTR<Tree> tree, EnvNode* outer);

    EnvNode(const EnvNode& other);

    EnvNode(EnvNode&& other) noexcept;

    EnvNode& operator=(const EnvNode& other);

    EnvNode& operator=(EnvNode&& other) noexcept;

    static EnvNode rootEnvNode(const PTR<CompilationUnitTree>& root);

    EnvNode dup(const PTR<Tree>& current_tree);

    EnvNode dupForClass(const PTR<ClassTree>& class_tree);

    EnvNode dupForMethod(const PTR<MethodTree>& method_tree);

    EnvNode dupForBlock(const PTR<BlockTree>& block_tree);

    PTR<PackageSymbol> findRootSymbol() const;

    PTR<ClassSymbol> findClassSymbol() const;

    PTR<MethodSymbol> findMethodSymbol() const;

    PTR<Symbol> findEnclosingSymbol() const;

    PTR<BlockTree> findEnclosingBlock() const;

    bool hasTreeKind(const TreeKind& kind, const TreeKind& stop_kind = TreeKind::kExpressionStatement) const;
  };

  /// 将 TreeKind 转为字符串输出
  /// @param kind TreeKind
  /// @return TreeKind 对应的字符串
  String treeKindToString(const TreeKind& kind);
  /// 将 {@struct CompilationUnitKind} 转为字符串输出
  /// @param kind {@struct CompilationUnitKind}
  /// @return {@struct CompilationUnitKind} 对应的字符串
  String unitKindToString(const CompilationUnitKind& kind);
  /// 将 MethodKind 转为字符串输出
  /// @param kind MethodKind
  /// @return MethodKind 对应的字符串
  String methodKindToString(const MethodKind& kind);
  /// 将 CodeKind 转为字符串输出
  /// @param kind CodeKind
  /// @return CodeKind 对应的字符串
  String codeKindToString(const CodeKind& kind);
  /// 将 CodeRefKind 转为字符串输出
  /// @param kind CodeRefKind
  /// @return CodeRefKind 对应的字符串
  String codeRefKindToString(const CodeRefKind& kind);
  /// 将 TiecodeToken 转为字符串输出
  /// @param token token值
  /// @return TiecodeToken 对应的字符串
  String tokenToString(const TiecodeToken& token);
}

#endif //TIEC_TREE_H
